接下來我們會仔細講述應該如何訓練並且測試自己的 MTCNN Model,使用的語言為 Pytorch,我們逐步帶著大家實作並且講解每一步。因為是此系列的第一段實作,因此我們還是會比較詳細的講,那等大家習慣了整格流程之後,後續的主題實作則會言簡意賅地跟大家講述。
實作MTCNN(Multi-task Cascaded Convolutional Networks)人臉偵測器需要使用 PyTorch,這是一個強大的深度學習框架。MTCNN是一種用於人臉偵測的前沿技術,它由三個網絡組成,每個網絡都負責不同的任務:檢測(detection)、對齊(alignment)和特徵提取(feature extraction)。在下面的示例中,我們將使用PyTorch實現MTCNN的檢測部分,也就是檢測人臉的網絡。完整的程式之後也會放連結上來給大家參考!
首先,確保你已經安裝了PyTorch
,可以通過以下方式進行安裝:
pip install torch torchvision
我們在這次實作中會使用到 WiderFace 這個資料集,請從官網下載,要下載Train & Validation 兩包資料集,下載後解壓縮並且放成這樣資料夾格式
./data_set/face_detection/
|-----WIDER_train/
| |----images/
|-----WIDER_val/
| |----images/
並且請下載這一份 label file,裡面包含著 Label ,格式為:
照片路徑 人臉框左上X 人臉框左上Y 人臉框右下X 人臉框右下Y
如果是多個人臉則會是:
照片路徑 第一個人臉框左上X 第一個人臉框左上Y 第一個人臉框右下X 第一個人臉框右下Y 第二個人臉框左上X 第二個人臉框左上Y 第二個人臉框右下X 第二個人臉框右下Y ...
因為檔案要嚇得比較久,所以我們今天資料集先等下載就好!
我們參考文中格式去使用 Pytorch 去建立以下模型,結構可參考這章提及的:
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import models
class PNet(nn.Module):
def __init__(self):
super(PNet, self).__init__()
# 網絡層的定義
self.conv1 = nn.Conv2d(3, 10, kernel_size=3, stride=1, padding=1)
self.prelu1 = nn.PReLU(10)
self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
self.conv2 = nn.Conv2d(10, 16, kernel_size=3, stride=1)
self.prelu2 = nn.PReLU(16)
self.conv3 = nn.Conv2d(16, 32, kernel_size=3, stride=1)
self.prelu3 = nn.PReLU(32)
# 檢測人臉的卷積層和輸出層, 預測 人臉/非人臉的分類, 人臉位置的偏移量
self.conv4_1 = nn.Conv2d(32, 2, kernel_size=1, stride=1)
self.conv4_2 = nn.Conv2d(32, 4, kernel_size=1, stride=1)
def forward(self, x):
"""
Arguments:
x: a float tensor with shape [batch_size, 3, h, w].
Returns:
out_cls: a float tensor with shape [batch_size, 2]. # 人臉/非人臉的分類
out_offset: a float tensor with shape [batch_size, 4]. # 人臉位置的偏移量
"""
# 前向傳播過程
x = self.conv1(x)
x = self.prelu1(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.prelu2(x)
x = self.conv3(x)
x = self.prelu3(x)
# 檢測人臉的輸出
out_cls = torch.sigmoid(self.conv4_1(x)) # 人臉/非人臉的分類
out_offset = self.conv4_2(x) # 人臉位置的偏移量
return out_cls, out_offset
# 初始化PNet模型
pnet = PNet()
上述程式定義了PNet,這是MTCNN中的第一個網絡,主要用於粗略檢測圖像中的人臉。這只是MTCNN的一部分,詳細的實做需要包括其他網絡(RNet和ONet)以及後處理步驟。要完整實現MTCNN,需要另外實現RNet和ONet,以及相關的後處理邏輯。
基本上建構邏輯與 PNet 相同我們都是根據原圖結構來建,注意ONet 一定要有預測出人臉關鍵點的分支喔(一個10維)
class RNet(nn.Module):
def __init__(self,):
super(RNet, self).__init__()
self.conv1 = nn.Conv2d(3, 28, kernel_size=3, stride=1, padding=1)
self.prelu1 = nn.PReLU(28)
self.pool1 = nn.MaxPool2d(3, 2, ceil_mode=True)
self.conv2 = nn.Conv2d(28, 48, kernel_size=3, stride=1, padding=1)
self.prelu2 = nn.PReLU(48)
self.pool1 = nn.MaxPool2d(3, 2, ceil_mode=True)
self.conv3 = nn.Conv2d(48, 64, kernel_size=2, stride=1, padding=1)
self.prelu3 = nn.PReLU(64)
self.conv4 = nn.Conv2d(576, 128, kernel_size=2, stride=1, padding=1)
self.prelu4 = nn.PReLU(128)
# 預測 人臉/非人臉的分類, 人臉位置的偏移量
self.linear5_1 = nn.Linear(128, 2)
self.linear5_2 = nn.Linear(128, 4)
def forward(self, x):
"""
Arguments:
x: a float tensor with shape [batch_size, 3, h, w].
Returns:
out_cls: a float tensor with shape [batch_size, 2]. # 人臉/非人臉的分類
out_offset: a float tensor with shape [batch_size, 4]. # 人臉位置的偏移量
"""
x = self.conv1(x)
x = self.prelu1(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.prelu2(x)
x = self.conv3(x)
x = self.prelu3(x)
# 攤平方便之後計算
x = x.transpose(3, 2).contiguous()
x = x.view(x.size(0), -1)
x = self.conv4(x)
x = self.prelu4(x)
# 檢測人臉的輸出
out_cls = torch.sigmoid(self.linear5_1(x)) # 人臉/非人臉的分類
out_offset = self.linear5_2(x) # 人臉位置的偏移量
return out_cls, out_offset
class ONet(nn.Module):
def __init__(self, is_train=False):
super(ONet, self).__init__()
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1)
self.prelu1 = nn.PReLU(32)
self.pool1 = nn.MaxPool2d(3, 2, ceil_mode=True)
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
self.prelu2 = nn.PReLU(64)
self.pool2 = nn.MaxPool2d(3, 2, ceil_mode=True)
self.conv3 = nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1)
self.prelu3 = nn.PReLU(64)
self.pool3 = nn.MaxPool2d(2, 2, ceil_mode=True)
self.conv4 = nn.Conv2d(64, 128, kernel_size=2, stride=1, padding=1)
self.prelu4 = nn.PReLU(128)
self.linear5 = nn.Linear(1152, 256)
self.drop = nn.Dropout(0.25)
self.prelu5 = nn.PReLU(256)
# 預測 人臉/非人臉的分類, 人臉位置的偏移量, 人臉5點關鍵點位置
self.linear6_1 = nn.Linear(256, 2)
self.linear6_2 = nn.Linear(256, 4)
self.linear6_3 = nn.Linear(256, 10)
def forward(self, x):
"""
Arguments:
x: a float tensor with shape [batch_size, 3, h, w].
Returns:
out_cls: a float tensor with shape [batch_size, 2]. # 人臉/非人臉的分類
out_offset: a float tensor with shape [batch_size, 4]. # 人臉位置的偏移量
out_landmark: a float tensor with shape [batch_size, 10]. #人臉5點關鍵點位置
"""
x = self.conv1(x)
x = self.prelu1(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.prelu2(x)
x = self.pool2(x)
x = self.conv3(x)
x = self.prelu3(x)
x = self.pool3(x)
x = self.conv4(x)
x = self.prelu4(x)
# 攤平方便之後計算
x = x.transpose(3, 2).contiguous()
x = x.view(x.size(0), -1)
x = self.linear5(x)
x = self.drop(x)
x = self.prelu5(x)
# 檢測人臉的輸出
out_cls = torch.sigmoid(self.linear6_1(x)) # 人臉/非人臉的分類
out_offset = self.linear6_2(x) # 人臉位置的偏移量
out_landmark = self.linear6_3(x) # 人臉5點關鍵點位置
return out_cls, out_offset, out_landmark
我們今天已經下載完資料集跟建好模型了,那明天就要來寫訓練根資料/預測處裡了!
1.https://pytorch.org/
2.http://shuoyang1213.me/WIDERFACE/
3.https://github.com/xuexingyu24/MTCNN_Tutorial/tree/master